package com.hzgj.bcl.soa.rpc.exception;

import java.io.PrintStream;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;

/**
 * 支持错误代码的异常类。
 */
public class FaultException extends RuntimeException {

    private int errorCode = -1;
    private Map<String, Object> data;

    public FaultException() {
    }

    public FaultException(String message) {
        super(message);
    }

    /**
     * 使用 MessageFormat.format 格式化，占位符格式为 {0} {1} {2}
     *
     * @param messageFormat
     * @param messageArgs
     */
    public FaultException(String messageFormat, Object... messageArgs) {
        super(MessageFormat.format(messageFormat, messageArgs));
    }

    public FaultException(int errorCode, String message) {
        super(message);
        this.errorCode = errorCode;
    }

    public FaultException(int errorCode, String messageFormat, Object... messageArgs) {
        this(errorCode, MessageFormat.format(messageFormat, messageArgs));
    }

    public FaultException(int errorCode, String message, Throwable cause) {
        super(message, cause);
        this.errorCode = errorCode;
    }

    public FaultException(Throwable cause) {
        super(cause);
    }

    public static <T extends ErrorInfo> FaultException of(T error) {
        return new FaultException(error.getCode(), error.getMessage());
    }

    public static <T extends ErrorInfo> FaultException of(T error, Object... messageArgs) {
        return new FaultException(error.getCode(), MessageFormat.format(error.getMessage(), messageArgs));
    }

    public static <T extends ErrorInfo> FaultException of(Throwable cause, T error) {
        return new FaultException(error.getCode(), error.getMessage(), cause);
    }

    public static <T extends ErrorInfo> FaultException of(Throwable cause, T error, Object... messageArgs) {
        return new FaultException(error.getCode(), MessageFormat.format(error.getMessage(), messageArgs), cause);
    }

    /**
     * 错误代码
     */
    public int getErrorCode() {
        return errorCode;
    }

    /**
     * 是否设置了错误（非零，非 -1）。
     *
     * @return
     */
    public boolean hasErrorCode() {
        return errorCode != 0 && errorCode != -1;
    }

    @Override
    public String toString() {
        String s = super.toString();
        if (hasErrorCode()) {
            s += " (errorCode: " + getErrorCode() + ")";
        }
        return s;
    }

    @Override
    public void printStackTrace(PrintStream s) {
        super.printStackTrace(s);
        if (data != null && data.size() > 0) {
            s.println();
            for (Map.Entry<String, Object> entry : data.entrySet()) {
                s.append("\t").append(entry.getKey()).append(": ");
                s.print(entry.getValue());
                s.println();
            }
        }
    }

    /**
     * 返回堆栈详情
     *
     * @return
     */
    public String getStackTraceString() {
        return Exceptions.getStackTrace(this);
    }

    /**
     * 获取自定义数据。
     *
     * @return
     */
    public Map<String, Object> getData() {
        if (data == null) {
            data = new HashMap<>();
        }
        return data;
    }
}
